﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using ufida.u9.ait.openapi.utils;
using UFIDA.U9.Base;
using UFIDA.U9.Base.Currency;
using UFIDA.U9.Base.Organization;
using UFIDA.U9.CBO.HR.Department;
using UFIDA.U9.CBO.HR.Operator;
using UFIDA.U9.CBO.SCM.Item;
using UFIDA.U9.CBO.SCM.PickList;
using UFIDA.U9.CBO.SCM.Warehouse;
using UFIDA.U9.ER.ERBP;
using UFIDA.U9.ISV.MO;
using UFIDA.U9.ISV.PMIssue;
using UFIDA.U9.ISV.PMIssue.Proxy;
using UFIDA.U9.MO.MO;
using UFIDA.U9.PM.PMIssue;
using UFIDA.U9.PM.PMIssue_Enum;
using UFIDA.U9.PM.PMIssueBP;
using UFIDA.U9.PM.PO;
using UFIDA.U9.PM.Rcv;
using UFIDA.U9.SM.DealerSO;
using UFSoft.UBF.Business;
using UFSoft.UBF.Execution.WorkManagers;

namespace ufida.u9.ait.openapi
{
    internal class PMIssueBase
    {
        public static PMIssueDoc DeleteDoc(PMIssueDoc doc)
        {
            DeletePMIssue4ExternalProxy proxy = new DeletePMIssue4ExternalProxy();
            proxy.PMIssueKeyDTOs = new List<PMIssueKeyDTOData>
                        {
                            new PMIssueKeyDTOData()
                            {
                                ID = doc.ID,
                            }
                        };
            bool ret = proxy.Do();
            if (!ret)
                throw new Exception($"删除单据失败!单号:[{doc.DocNo}]");
            return doc;
        }
        public static PMIssueDoc ApproveDocEx(DocDTOData dto, PMIssueDoc doc)
        {
            if (!String.IsNullOrEmpty(dto.DocDate))
            {
                //修改日期
                using (ISession session = Session.Open())
                {
                    doc.BusinessDate = DateTime.Parse(dto.DocDate);//单据日期
                    doc.BusinessCreatedOn = doc.BusinessDate;//确认日期
                    //doc.IssueItemOn = doc.BusinessDate;//发料确认日期
                    //foreach (var line in doc.IssueDocLines)
                    //{
                    //    line.ActualIssueDate = doc.BusinessDate;//实发日期
                    //}
                    session.Commit();
                }
            }
            return ApproveDoc(doc);
        }
        public static PMIssueDoc ApproveDoc(PMIssueDoc doc)
        {
            U9Utils.ClearCache();

            doc = doc.Key.GetEntity();
            if (doc.DocState != PMIssueDocState.Opened && doc.DocState != PMIssueDocState.Approving)
            {
                //throw new Exception($"单据[{doc.DocNo}]状态不为开立或提交");
                //单据类型:确认方式=及时确认时,单据自动审核
                return doc;
            }

            //调用BP
            //第一次调用 状态 开立->审核中
            ApprovePMIssueBP bp1 = new ApprovePMIssueBP();
            bp1.PMIssueDoc = doc.Key;
            bp1.CurrentSysVersion = doc.SysVersion;
            bp1.Do();
            //第二次调用 状态 审核中->已审
            if (doc.DocState == PMIssueDocState.Approving)
            {
                ApprovePMIssueBP bp2 = new ApprovePMIssueBP();
                bp2.PMIssueDoc = doc.Key;
                bp2.CurrentSysVersion = doc.SysVersion;
                bp2.Do();
            }

            return doc;
        }

        public static PMIssueDoc CreateDoc(PMIssueDocAITDTOData dto)
        {
            PMIssueDoc doc = null;
            using (ISession session = Session.Open())
            {
                doc = CreateHead(dto);
                CeateLines(dto, doc);
                session.Commit();
            }
            return doc;
        }

        private static PMIssueDoc CreateHead(PMIssueDocAITDTOData dto)
        {
            PMIssueDoc doc = PMIssueDoc.Create();

            //单头赋值
            doc.DocNo = "自动编号";//单号
            doc.Org = Context.LoginOrg;//组织
            doc.IssueOrg = doc.Org;

            if (dto.IssueDocType == null) throw new Exception("单据类型 为空!");
            doc.IssueDocType = EntityUtils.GetEntityByCode<PMIssueDocType>(dto.IssueDocType.Code);
            if (string.IsNullOrEmpty(dto.BusinessDate))
                doc.BusinessDate = DateTime.Now;
            else
                doc.BusinessDate = DateTime.Parse(dto.BusinessDate);
            doc.BusinessCreatedOn = doc.BusinessDate; //确认日期
            doc.HandleDept = EntityUtils.GetEntityByCode<Department>(dto.HandleDept);//发料部门
            doc.HandlePerson = EntityUtils.GetEntityByCode<Operators>(dto.HandlePerson);//发料人
            if (doc.HandlePerson != null)
            {
                doc.HandleDept = doc.HandlePerson.Dept;
            }

            //扩展字段
            if (dto.DescFlexField!=null)
            {
                doc.DescFlexField = new UFIDA.U9.Base.FlexField.DescFlexField.DescFlexSegments();
                DTOUtils.DTOPropCopy(dto.DescFlexField, doc.DescFlexField);
            }

            //其他赋值
            doc.WorkFlowID = Guid.Empty;
            doc.StateMachineID = Guid.Empty;

            //领退类型
            //Issue	领料 0
            //Recede	退料 1
            doc.IssueDirection = IssueDirectionEnum.GetFromValue(dto.IssueDirection);

            return doc;
        }

        private static void CeateLines(PMIssueDocAITDTOData dto, PMIssueDoc doc)
        {
            //行赋值
            foreach (var linedto in dto.IssueDocLines)
            {
                PMIssueDocLine line = PMIssueDocLine.Create(doc);
                LineDefault(line,linedto);
                LineQty(line, linedto);
                LineSrcDoc(line, linedto);
            }
        }

        private static void LineSrcDoc(PMIssueDocLine line, IssueDocLinesAITDTOData linedto)
        {
            PMIssueDoc doc = line.PMIssueDoc;

            //来源单据处理
            //IssueDirection 领退类型
            if (doc.IssueDirection == IssueDirectionEnum.Issue)
            {
                //领退类型=领料
                FromPickList(line, linedto);
            }
            else if (doc.IssueDirection == IssueDirectionEnum.Recede)
            {
                //领退类型=退料
                FromIssue(line, linedto);
            }
        }

        private static void LineQty(PMIssueDocLine line, IssueDocLinesAITDTOData linedto)
        {
            ItemMaster item = line.Item;

            //单位处理
            line.WhUOM = item.InventoryUOM;//库存单位
            line.StoreBaseUOM = line.WhUOM.BaseUOM;
            line.IssueUOM = item.MaterialOutUOM;//发料单位
            line.IssueBaseUOM = line.IssueUOM.BaseUOM;
            line.CoUOM = item.CostUOM;//成本单位
            line.CostBaseUOM = item.CostUOM.BaseUOM;

            //数量处理
            if (linedto.IssueQty == 0)
                throw new Exception("IssueQty必填");
            line.IssueQty = linedto.IssueQty;//应发数量
            line.IssuedQty = linedto.IssuedQty>0? linedto.IssuedQty:linedto.IssueQty;//实发数量
            line.IssuedQtyByWhUOM = line.IssuedQty;//实发数量(库存)
            line.IssuedQtyByCoUOM = linedto.IssuedQtyByCoUOM > 0 ? linedto.IssuedQtyByCoUOM : line.IssueQty;//实发数量(成本)
            //转化率
            line.IBUToCBURate = line.IssuedQtyByCoUOM / line.IssuedQtyByWhUOM;//库存-成本
            line.IBUToSBURate = 1;//发料-库存
            line.IUToIBURate = 1;//发料主-副
            line.SUToSBURate = 1;//库存主-副
            line.CUToCBURate = 1;//成本主-副
        }

        /// <summary>
        /// 设置初始默认值
        /// </summary>
        /// <param name="line"></param>
        /// <param name="linedto"></param>
        private static void LineDefault(PMIssueDocLine line, IssueDocLinesAITDTOData linedto)
        {
            PMIssueDoc doc = line.PMIssueDoc;
            //行号
            if (linedto.LineNum > 0)
            {
                line.LineNum = linedto.LineNum;
            }
            else
            {
                line.LineNum = doc.IssueDocLines.Count*10;
            }
            //组织
            line.OwnerOrg = doc.Org;
            line.BenifitOrg = doc.Org;
            //料品
            if (linedto.Item == null)
                throw new Exception($"物料[Item]为空");
            ItemMaster item = ItemMaster.Finder.Find($"Code='{linedto.Item.Code}'");
            if (item == null)
                throw new Exception($"物料编码[{linedto.Item.Code}]查找失败!");
            line.Item = item;
            //等级
            if (linedto.Grade >= 0)
            {
                line.Grade = GradeEnum.GetFromValue(linedto.Grade); //等级
                //if (String.IsNullOrEmpty(line.Grade.Name))
                //    throw new Exception("等级传入错误");
            }
            if (linedto.Element >= 0)
            {
                line.Element = ElementEnum.GetFromValue(linedto.Element); //成分
            }
            //部门
            if (String.IsNullOrEmpty(linedto.IssueDept?.Code))
            {
                line.IssueDept = doc.HandleDept;
            }
            else
            {
                line.IssueDept = EntityUtils.GetEntityByCode<Department>(linedto.IssueDept);
            }
            //扩展字段
            if (linedto.DescFlexField != null)
            {
                line.DescFlexField = new UFIDA.U9.Base.FlexField.DescFlexField.DescFlexSegments();
                DTOUtils.DTOPropCopy(linedto.DescFlexField, line.DescFlexField);
            }
            //其他赋值
            if (linedto.Currency == null)
            {
                line.Currency = EntityUtils.GetEntityByCode<Currency>("C001");
            }
            else
            {
                line.Currency = EntityUtils.GetEntityByCode<Currency>(linedto.Currency);
            }
            if (linedto.Wh == null)
                throw new Exception($"仓库[Wh]为空");
            line.Wh = EntityUtils.GetEntityByCode<Warehouse>(linedto.Wh.Code);//存储地点
            line.CostField = EntityUtils.getCostField(linedto.Wh.Code); //成本域
            if (linedto.Bin != null && !string.IsNullOrEmpty(linedto.Bin.Code))
            {
                line.Bin = EntityUtils.GetBin(linedto.Wh.Code, linedto.Bin.Code);//库位
            }
            //批号处理
            if (!string.IsNullOrEmpty(linedto.LotNo))
            {
                line.LotNo = linedto.LotNo;//批号
                UFIDA.U9.Lot.LotMaster lot = EntityUtils.GetLot(linedto.LotNo, linedto.Item.Code);
                line.LotMaster = lot;//批次主档
                line.LotEffectivedate = lot.EffectiveDatetime;//生效日期
                line.LotDisableDate = lot.InvalidTime;//失效日期
            }

            //其他
            line.PlanIssueDate = doc.BusinessDate;//应发日期
            line.SUToSBURate = 1;
            line.IUToIBURate = 1;
            line.IBUToSBURate = 1;
            line.IBUToCBURate = 1;
            line.CUToCBURate = 1;
            if (linedto.StorageType > -1)
            {
                line.StorageType = UFIDA.U9.CBO.Enums.StorageTypeEnum.GetFromValue(linedto.StorageType);//存储类型
            }
            else
            {
                line.StorageType = UFIDA.U9.CBO.Enums.StorageTypeEnum.GetFromValue(4);//存储类型
            }
        }

        /// <summary>
        /// 依据备料领料
        /// 支持无备料领料
        /// </summary>
        /// <param name="line"></param>
        /// <param name="linedto"></param>
        private static void FromPickList(PMIssueDocLine line, IssueDocLinesAITDTOData linedto)
        {
            if (linedto.POPick == null || string.IsNullOrEmpty(linedto.POPick.SrcDocNo))
                throw new Exception("POPick为空或SrcDocNo为空");

            //来源单据-委外订单备料
            SCMPickList pickList;//备料行
            if (linedto.POPick.SrcDocSubLineNo >= 0)
            {
                //有备料领料
                //查找备料行
                string path = $"PickLineNo={linedto.POPick.SrcDocSubLineNo} and PicKHead.POLine.DocLineNo={linedto.POPick.SrcDocLineNo} and PicKHead.POLine.PurchaseOrder.DocNo='{linedto.POPick.SrcDocNo}'";
                pickList = SCMPickList.Finder.Find(path);
                if (pickList == null)
                {
                    throw new Exception($"查找委外订单备料失败!path:{path}");
                }
                //校验
                if (linedto.Item.Code != pickList.ItemInfo.ItemCode)
                    throw new Exception($"来源物料[{pickList.ItemInfo.ItemCode}]与传入物料[{linedto.Item.Code}]不同");
                //应发数量 = 备料实际用量-备料已发数量
                line.IssueQty = pickList.ActualReqQty - pickList.IssuedQty;
            }
            else
            {
                //无备料领料
                //创建备料行
                pickList = CreatePickList(linedto);
            }

            //来源赋值
            line.POPick = pickList;//委外订单备料
            line.POLine = pickList.PicKHead.POLine;//委外订单行
            line.SubconstractItem = pickList.PicKHead.POLine.ItemInfo.ItemID;//委外料品
            line.SubconstractSupplier = pickList.PicKHead.POLine.PurchaseOrder.Supplier.Supplier;//委外商
        }

        /// <summary>
        /// 创建备料行
        /// </summary>
        /// <param name="linedto"></param>
        /// <returns></returns>
        /// <exception cref="Exception"></exception>
        private static SCMPickList CreatePickList(IssueDocLinesAITDTOData linedto)
        {
            SCMPickList pickList;
            string path = $"POLine.DocLineNo={linedto.POPick.SrcDocLineNo} and POLine.PurchaseOrder.DocNo='{linedto.POPick.SrcDocNo}'";
            PicKHead head = PicKHead.Finder.Find(path);
            if (head == null)
            {
                //备料为空时,需要创建备料单头
                //throw new Exception($"查找委外订单备料!path:{path}");
                path = $"DocLineNo={linedto.POPick.SrcDocLineNo} and PurchaseOrder.DocNo='{linedto.POPick.SrcDocNo}'";
                POLine poline = POLine.Finder.Find(path);
                if (poline == null)
                {
                    throw new Exception($"查找委外订单行失败,path:{path}");
                }
                using (ISession session = Session.Open())
                {
                    head = SubPOBase.CreatePicKHead(poline.PurchaseOrder, poline);
                    session.Commit();
                }
            }

            //获取最大行号
            int maxlineno = 0;
            foreach (var pickline in head.SCMPickListS)
            {
                if (pickline.PickLineNo > maxlineno)
                    maxlineno = pickline.PickLineNo;
            }
            //需要先创建委外备料行
            using (ISession session = Session.Open())
            {
                maxlineno += 10;
                SCMPickListAITDTOData picklinedto = new SCMPickListAITDTOData();
                picklinedto.PickLineNo = (short)maxlineno;
                picklinedto.ItemInfo = new CopyOfItemInfoData()
                {
                    ItemCode = linedto.Item.Code,
                };
                picklinedto.ActualReqQty = linedto.IssueQty;
                pickList = SubPOBase.CreateSCMPickLine(head, picklinedto);

                session.Commit();
            }

            return pickList;
        }

        /// <summary>
        /// 退料
        /// 依据来源领料单赋值
        /// </summary>
        /// <param name="line">领料行</param>
        /// <param name="linedto">领料单DTO</param>
        private static void FromIssue(PMIssueDocLine line, IssueDocLinesAITDTOData linedto)
        {
            if (linedto.RecedeIssueSourceLine == null) throw new Exception("RecedeIssueSourceLine为空");
            string path = $"LineNum={linedto.RecedeIssueSourceLine.SrcDocLineNo} and PMIssueDoc.DocNo='{linedto.RecedeIssueSourceLine.SrcDocNo}'";
            PMIssueDocLine srcline = PMIssueDocLine.Finder.Find(path);
            if (srcline == null) throw new Exception($"查询来源领料行失败!path:[{path}]");

            line.RecedeIssueSourceLine = srcline;//退料原领料单明细
            line.POPick = srcline.POPick;//订单备料
            line.POLine = srcline.POLine;//委外订单行
            line.SubconstractItem = srcline.SubconstractItem;//委外料品
            line.SubconstractSupplier = srcline.SubconstractSupplier;//委外商

            line.Price = srcline.Price;//单价
            line.Currency = srcline.Currency;//币种
            line.CostField = srcline.CostField;//成本域
            line.CostAmt = srcline.CostAmt;//成本金额
        }
    }
}
